/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.seari.ibpPanleMidware.main;

import com.ghgande.j2mod.modbus.io.ModbusTCPTransaction;
import com.ghgande.j2mod.modbus.msg.ReadInputRegistersRequest;
import com.ghgande.j2mod.modbus.msg.ReadInputRegistersResponse;
import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersRequest;
import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersResponse;
import com.ghgande.j2mod.modbus.net.TCPMasterConnection;
import com.ghgande.j2mod.modbus.procimg.Register;
import com.seari.commonutils.redis.JedisUtilProxy;
import com.seari.commonutils.redis.ex.JedisNotInitializeException;
import com.seari.ibpPanleMidware.bean.StationConfig;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;

/**
 *
 * @author Rainbow
 */
@Component
@Scope("prototype")
public class IbpFanWorker implements Runnable
{
    public boolean terminate = false;
    public static Map<String,Map<Integer,Integer>> stationFanMap;
    public static Map<String,String[]> groupIpMap = new HashMap<>();
    public static String key;
    @Override
    public void run()
    {
        key = StartUpClass.stationFanConfigs.get(0).getDataTableName();
        Jedis jedis = null;
        try
        {
            jedis = JedisUtilProxy.getJedis();
            while (!terminate)
            {
                if (jedis.isConnected())
                {
                    for (Map.Entry<String, Map<Integer, Integer>> entry : stationFanMap.entrySet())
                    {
                        Map<Integer, Integer> addrValueMap = entry.getValue();
                        readRegister(addrValueMap, entry.getKey());
                    }
                    updateRedisData(jedis);
                }else {
                    //JEDIS连接失败时将当前连接回收至连接池，并获取新连接
                    JedisUtilProxy.close(jedis);
                    JedisUtilProxy.getJedisPool().returnBrokenResource(jedis);
                    jedis = JedisUtilProxy.getJedis();
                }
                TimeUnit.SECONDS.sleep(2);
            }
        } catch (Exception e)
        {
            e.printStackTrace();
        }finally{
            JedisUtilProxy.close(jedis);
            //终止标志不为真时，认为此线程非正常退出，进行线程重启
            if(!terminate)
            {
                try
                {
                        TimeUnit.SECONDS.sleep(2);
                        Thread.currentThread().interrupt();
                } catch (Exception e2)
                {
                        // TODO: handle exception
                }
                new Thread(this).start();
            }
        }
    }
    
    private void updateRedisData(Jedis jedis) throws JedisNotInitializeException
    {
        try
        {
            //jedis.hset(stationConfig.getDataTableName(), stationConfig.getStationId() + "", data[0] + "");
            //jedis.hset(stationConfig.getDataTableName(), stationConfig.getStationId() + "_FAS", data[1] + "");
            Map<String,String> resultMap = new HashMap<>();
            for (StationConfig stationFanConfig : StartUpClass.stationFanConfigs)
            {
                //无偏移量时直接取值
                if("nooffset".equals(stationFanConfig.getDataExtend3()))
                {
                    int value = stationFanMap.get(stationFanConfig.getDataGroup()).get(stationFanConfig.getDataAddress());
                    resultMap.put(stationFanConfig.getDataExtend1(), value + "");
                }else{
                    //有偏移量时进行偏移量计算
                    int value = getBit(stationFanMap.get(stationFanConfig.getDataGroup()).get(stationFanConfig.getDataAddress()),Integer.parseInt(stationFanConfig.getDataExtend2()));
                    resultMap.put(stationFanConfig.getDataExtend1(), value + "");
                }
            }
            jedis.hmset(key, resultMap);
        } catch (Exception e)
        {
            //异常处理时重新获取JEDIS实例，防止异常后JEDIS未归还至连接池
            e.printStackTrace();
            JedisUtilProxy.close(jedis);
            jedis = JedisUtilProxy.getJedis();
        }
    }
    
    private void readRegister(Map<Integer, Integer> addrValueMap,String group)
    {
        TCPMasterConnection con = null;
        String ipStrs[] = groupIpMap.get(group);
        for (String ipStr : ipStrs)
        {
            try 
            {
                InetAddress addr = InetAddress.getByName(ipStr);
                /*TCPMasterConnection */
                con = new TCPMasterConnection(addr);
                con.setPort(502);
                con.connect();
                for (Map.Entry<Integer, Integer> entry : addrValueMap.entrySet())
                {
                    ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(entry.getKey(),1);
                    req.setUnitID(1);
                    ModbusTCPTransaction trans = new ModbusTCPTransaction(con);
                    trans.setRequest(req);
                    trans.execute();
                    ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) trans.getResponse();
                    //ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) con.getModbusTransport().readResponse();
                    addrValueMap.put(entry.getKey(), res.getRegisterValue(0));
                }
                //data[1] = getExtendValue(stationConfig, con);
                break; //读取成功时直接BREAK出循环
            } catch (Exception e) {
                //读取异常的时候以-1返回
                e.printStackTrace();
                System.out.println("读取异常的时候以-1返回------>ip"+ipStr);
            }finally{
                if(con!=null)
                {
                    con.close();
                }
            }
        }
    }
    
    public void init()
    {
        stationFanMap = StartUpClass.stationFanMap;
        groupIpMap = StartUpClass.groupIpMap;
    }
    
    //获取 整数 num 的第 i 位的值
    private static int getBit(int num, int i)
    {
        //true 表示第i位为1,否则为0
        if(((num & (1 << i)) != 0))
        {
            return 1;
        }else{
            return 0;
        }
    }
}
